#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>


//int main()
//{
//	int a = -7;//
//	int b = a >> 1;
	//右移操作符的运算结果，在大部分编译器中都是算数右移
	//算数右移是指给这个数的补码右移，
	// 丢掉最后一位二进制数后，在第一位补上符号位
	//-7的补码是11111111 11111111 11111111 11111001，
	// 执行上述的编译操作后
	//变为11111111 11111111 11111111 11111100，这是补码
	//人在计算这个补码对应的十进制数的时候，通过先减一，
	//得到11111111 11111111 11111111 11111011,
	// 再对非符号位取反的方式后得到
	//10000000 00000000 00000000 00000100，其对应的十进制数是-4
//	printf("b = %d\n", b);//
//	return 0;//
//}

//int main()
//{
	//int a = -7;

	//-7的原码是10000000 00000000 00000000 00000111
	//-7的反码是原码的符号位不变,其它位按位取反,
	// 得11111111 11111111 11111111 11111000
	//-7的补码是反码加1，得11111111 11111111 11111111 11111001
	//-7在计算机中是按补码的形式进行存储的

	//int b = a << 1;

	//左移操作符<<就是将补码开始的那位去掉，
	// 其它位全部左移，最后一位为0
	//a << 1的运算结果就是11111111 11111111 11111111 11111010
	
	//printf("b = %d\n", b);
	
	//打印的时候，打出来的是十进制数，人在计算这个十进制数时
	//最好通过原码进行计算，
	// 也就是通过补码11111111 11111111 11111111 11111010找到
	//其对应的原码，应该是10000000 00000000 00000000 00001110
	//仍把第一位看为符号位，可知其对应的十进制数为-14
//	return 0;//
//}//以上分析只针对整型数据


//练习1：
//计算一个整数对应的补码中1的个数
//int count1(int n1)
//{
//	int count = 0;
//	while (n1)
//	{
//		if (n1 & 1)
//		{
//			count++;
//		}
//		n1 >>= 1;
//	}
//	return count;
//}
//int main()
//{
//	int n = 0;//
//	int r = 0;
//	scanf("%d", &n);
//	if (n < 0)
//	{
//		int tmp = n & 0x7FFFFFFF;
//		r = count1(tmp);
//		printf("%ld\n", r + 1);
//	}
//	else
//	{
//		r = count1(n);
//		printf("%ld\n",r);
//	}
//	
//	return 0;//
//}

//int main()
//{
//	int a = -2;
//	int r = a >>= 1;
//	printf("%d\n", r);
//
//	return 0;
//}

//int main()
//{
//	int a = 3;
//	a >>= 1;
//	int flag = 3;
//	if (!flag)
	//只有当flag等于0时，通过!操作符，才能进入if后的语句
	//只要flag不等于0，都不会进入if后的语句
	//{
	//	;
	//}
	//int b = 3;//
	//int n = sizeof(int);
	//sizeof 计算的是类型所创建的变量占据空间的大小，单位是字节
	//sizeof 是操作符，不是函数，括号不是必要的，
	//sizeof a 是对的，但sizeof int是错的
	//if ("abc" == "bcdef")
	//这里括号里比较的是"abc"中a的地址 和 "bcdef"中b的地址是否相等
	//{
	//	;
	//}
	//int c = 0;//
	//printf("%d\n", ~c);
	//~c是指将c这个整形数据在计算机中存储的补码按位取反
	//00000000 00000000 00000000 00000000按位取反得
	//11111111 11111111 11111111 11111111,
	// 人们要要算出这个补码对应的十进制数，应通过原码
	//10000000 00000000 00000000 00000001，对应十进制中的-1 
//	return 0;
//}

//练习2：
//写一个程序，分别完成：将a的  补码的从低到高数的第i+1位  置1
// a的  补码的从低到高数的第k+1位  置0
//int main()
//{
//	int a = 13;//
//	a |= (1 << 4);//
//	printf("%d\n", a);//打印输出29
//	a &= (~(1 << 4));//
//	printf("%d\n", a);//打印输出13
//	
//	int b = (int)3.14;//将3.14理解成一个整形数据
//
//	return 0;
//}

//int main()
//{
//	int m = 0;//
//	int n = 1;//
//	int p = m || n;
//	//逻辑或只关注符号两端的运算结果是否为1
//	printf("%d\n", p);
//	int i = 0, a = 0, b = 2, c = 3, d = 4;//
//	i = a++ && ++b && d++;
//	//只要逻辑与&&语句中较为靠前的表达式算出来的值为0
//	//则后面的所有表达式都不会执行，也就不会产生任何结果
//	printf("a = %-3d b = %-3d c = %-3d d = %-3d", a, b, c, d);//
//	return 0;//
//}

//int main()
//{
//	int a = 3;//
//	int b = 0;//
//	if (a > 5)
//	{
//		b = 3;//
//	}
//	else
//	{
//		b = -3;//
//	}
//	b = (a > 5 ? 3 : -3);//这句话等价于上述的if else语句
//	return 0;//
//}

#include <string.h>

//练习14;
//写一个结构体类型，并通过结构体打印一个学生的名字，年纪，分数 
struct Stu
{
	char name[20];// 
	int age;
	double score;
};
//void set_stu(struct Stu* ps)
//{
//	strcpy((*ps).name, "zhangsan");
	//1、当set_stu用形参接收了一个结构体指针之后，
	// 应该使用解引用操作访问结构体中的name分量
	//2、即使是(*ps).name，也不能把整个的字符串直接赋值进去，
	// 因为要把一个数组中的元素一个个的传给另外一个数组中的元素时，
//	(*ps).age = 25;//
//	(*ps).score = 100.0;//
//}
//点操作符 . 的左边是结构体的对象，
//其值时结构体的名字，右边是结构体中声明时的成员
//这个函数也可以写成如下程序
void set_stu(struct Stu* ps)
{
	strcpy(ps->name, "zhangsan");
	ps->age = 25;//
	ps->score = 100.0;//
}
//->操作符的左边是一个结构体指针，右边是结构体中声明时的成员

//所写的这个结构体打印函数有一个缺点
//他用一整个结构体类型的形参对原先结构体的所有内容进行拷贝，
// 这导致空间占用过大
//此函数所传的形参数据类型和set_stu所传的形参数据类型 可以不同是因为：
//这里并不需要改动main函数中定义的结构体s的任何一个分量的内容
void print_stu(struct Stu ss)
{
	printf("%s %d %lf\n", ss.name, ss.age, ss.score);
}
int main()
{
	struct Stu s = { 0 };//
	set_stu(&s);
	print_stu(s);//
	return 0;//
}

